package com.learning.spring.ioc.life;

import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;

/**
 * ClassName: LifeCycleInBeanFactory
 * Description: BeanFactory 中 bean 的生命周期
 * Date: 2018/8/3 11:01 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class LifeCycleInBeanFactory {

    public static void main(String[] args) {
        test2();
    }

    /**Ordered
     * 两层意义：
     * 1. Bean 的作用范围
     * 2. 实例化bean 时经历的一系列阶段
     */
    static void test() {
    }


    /**
     * BeanFactory 中 bean 的生命周期
     * 1. getBean()  先容器请求一个 Bean
     * 2. 容器如果注册了
     */
    static void test2() {

        // BeanFactory 容器初始化
        ClassPathResource resource = new ClassPathResource("spring-context.xml");
        DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
        reader.loadBeanDefinitions(resource);

        System.out.println("~~~~~~~~~ BeanFactory 容器初始化 完成~~~~~~~~~~~");

        // 向容器中注册 BeanPostProcessor ，调用顺序与注册顺序无关（实现 Ordered 接口确定调用顺序）
        factory.addBeanPostProcessor(new LifeCycleBeanPostProcessor());

        // 向容器中注册 InstantiationAwareBeanPostProcessorAdapter
        factory.addBeanPostProcessor(new LifeCycleBeanAwareProcessor());

        System.out.println("~~~~~~~~~ 开始从 BeanFactory 容器中获取 Bean~~~~~~~~~~~");
        // 从容器中获取 Bean
        LifeCycleBean lifeCycleBean = factory.getBean("lifeCycleBean", LifeCycleBean.class);
        lifeCycleBean.setName("Sam life Cycle Bean");

        LifeCycleBean lifeCycleBean1 = factory.getBean("lifeCycleBean", LifeCycleBean.class);
        System.out.println(" 两次获取的Bean 对象是否为用一个： " + (lifeCycleBean == lifeCycleBean1));

        // 关闭容器
        factory.destroySingletons();

        /*
        ~~~~~~~~~ BeanFactory 容器初始化 完成~~~~~~~~~~~
        ~~~~~~~~~ 开始从 BeanFactory 容器中获取 Bean~~~~~~~~~~~
        调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法
        调用 LifeCycleBean 构造函数
        调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
        调用 InstantiationAwareBeanPostProcessor.postProcessPropertyValues() 方法
        调用 BeanNameAware.setBeanName() 方法
        调用 BeanFactoryAware.setBeanFactory() 方法
        调用 BeanPostProcessor.postProcessBeforeInitialization() 方法
        调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization() 方法
        调用 InitializingBean.afterPropertiesSet() 方法
        init-method 指定的初始化方法
        调用 BeanPostProcessor.postProcessAfterInitialization() 方法
        调用 InstantiationAwareBeanPostProcessor.postProcessAfterInitialization() 方法
        设置 setName 属性
        两次获取的Bean 对象是否为用一个： true
        调用 DisposableBean.destroy() 方法
        destroy-method 指定的销毁方法
        */
    }

    /**
     * Bean 生命周期接口的探讨
     * 1. Bean 的生命周期接口（BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean），如果要使用，会与spring框架耦合
     * 2. 其init-method 、destroy-method 属性指定初始化与销毁方法，和实现InitializingBean、DisposableBean是一样的，推荐使用属性指定
     * 3. Bean 的一个后置处理器 InitDestroyAnnotationBeanPostProcessor 针对 标注了@PostConstruct @PreDestroy 的 Bean 进行处理
     * 4. BeanFactoryAware 接口让Bean 感知容器（BeanFactory 实例），BeanNameAware 接口让Bean 获取配置文件中对应的配置名称。一般情况下，不需要关心。
     * 5. 综上，一般情况下，不需要关系 BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean 这4个接口
     * <p>
     * BeanPostProcessor：后置处理接口，可以向插件一样注册到容器中，为容器提供额外的功能。非常重要
     */
    static void test3() {

    }

}
